#pragma once

#include "Scene.hpp"
#include "VariableManager.hpp"
#include "VariableTypes.hpp"
#include "MathVariableTypes.hpp"

class Multishader;
class D3dTextureFromFile;
class StaticEnumType;

class SingleColorSky : public ISky, public IParamObject
{
public:
	static VariableManager & GetVarMan();

	SingleColorSky();

	const COLORF & GetColor() const { return m_Color; }
	void SetColor(const COLORF &v) { m_Color = v; }

	virtual bool Render(const ParamsCamera &camera);

	virtual void GetParamValue(uint id, void *outData) const;
	virtual void SetParamValue(uint id, const void *inData);

private:
	static VariableManager s_VarMan;

	COLORF m_Color;
};

struct CylinderSkyDesc : public ISimpleParamObject
{
	uint SegmentCount;
	VEC3 Axes[3];

	CylinderSkyDesc()
	: SegmentCount(8)
	{
		Axes[0] = VEC3_POSITIVE_X;
		Axes[1] = VEC3_POSITIVE_Y;
		Axes[2] = VEC3_POSITIVE_Z * 8.f;
	}

	virtual void SyncParamValue(uint id, void *data, bool set)
	{
		switch (id)
		{
		SYNC_PARAM_VAL(0, uint, SegmentCount)
		SYNC_PARAM_VAL(1, VEC3, Axes[0])
		SYNC_PARAM_VAL(2, VEC3, Axes[1])
		SYNC_PARAM_VAL(3, VEC3, Axes[2])
		default: assert(0);
		}
	}

	static VariableManager & GetVarMan()
	{
		if (!s_VarMan.IsInitialized())
		{
			s_VarMan.AddVar(new Uint32Variable("Segment Count", 0, 0, 3, 0xffffffff, 1));
			s_VarMan.AddVar(new Vec3Variable("Axes 0", 1, 0));
			s_VarMan.AddVar(new Vec3Variable("Axes 1", 2, 0));
			s_VarMan.AddVar(new Vec3Variable("Axes 2", 3, 0));
			s_VarMan.FinishInit();
		}
		return s_VarMan;
	}

private:
	static VariableManager s_VarMan;
};

class CylinderSky : public ISky, public IParamObject
{
public:
	static VariableManager & GetVarMan();

	enum BLEND_MODE
	{
		BLEND_ADD,
		BLEND_LERP,
		BLEND_COUNT
	};
	static const char * BLEND_MODE_NAMES[];

	MATRIX TexTransforms_C[4], TexTransforms_T[4];
	BLEND_MODE BlendModes[4]; // BlendModes[0] is ignored.
	COLORF Colors[4];
	COLORF FogColor;
	float FogBegPercent, FogEndPercent;

	CylinderSky(const CylinderSkyDesc &desc);
	~CylinderSky();

	// Layer count between 1 and 4. Default: 1.
	uint GetLayerCount() const { return m_LayerCount; }
	void SetLayerCount(uint v);
	D3dTextureFromFile * GetTexture(uint layer) { return m_Textures[layer]; }
	void SetTexture(uint layer, D3dTextureFromFile *texture);

	virtual bool Render(const ParamsCamera &camera);

	virtual void GetParamValue(uint id, void *outData) const;
	virtual void SetParamValue(uint id, const void *inData);

private:
	static VariableManager s_VarMan;
	static StaticEnumType *s_BlendEnumType;

	Multishader *m_Shader;
	IDirect3DVertexBuffer9 *m_VB;
	IDirect3DIndexBuffer9 *m_IB;
	uint m_LayerCount;
	D3dTextureFromFile *m_Textures[4];
	uint m_SegmentCount, m_VertexCount, m_TriangleCount;

	void CreateBuffers(uint segmentCount, const VEC3 axes[3]);
};
